package com.njcb.ams.service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import com.njcb.ams.repository.entity.SysTradeLogExample;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.njcb.ams.repository.dao.SysTradeLogDAO;
import com.njcb.ams.repository.entity.SysTradeLog;
import com.njcb.ams.factory.domain.AppContext;
import com.njcb.ams.support.exception.ExceptionUtil;

/**
 * 日志管理类
 *
 * @author liuyanlong
 */
@Service
public class LogManageService {
    private static final Logger logger = LoggerFactory.getLogger(LogManageService.class);
    @Autowired
    private SysTradeLogDAO tradeLogDAO;
    @Autowired
    private PlatformTransactionManager transactionManager;

    private static LinkedBlockingQueue<SysTradeLog> tradeLogs = new LinkedBlockingQueue<SysTradeLog>();

    private static LogManageService logManageService = null;

    public static LogManageService getInstance() {
        if (null == logManageService) {
            logManageService = AppContext.getBean(LogManageService.class);
        }
        return logManageService;
    }

    public static void init() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        final long deadline = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(1000);
                        List<SysTradeLog> billList = new ArrayList<SysTradeLog>();
                        while (deadline - System.nanoTime() >= 0 && billList.size() <= 200) {
                            SysTradeLog billMessage = tradeLogs.poll(100, TimeUnit.MILLISECONDS);
                            if (billMessage != null) {
                                billList.add(billMessage);
                            }
                        }
                        if (billList.size() > 0) {
                            logger.info("写入tradeLog长度{}", billList.size());
                            LogManageService.getInstance().saveLogBatch(billList);
                        }
                    } catch (Throwable e) {
                        logger.error(e.getMessage(), e);
                    }
                }
            }
        }, "AMS-tradeLogInsert").start();
    }

    /**
     * 异步写入日志
     *
     * @param tradeLog
     */
    public void asynAddLog(SysTradeLog tradeLog) {
        if (tradeLogs.size() > 10000) {
            ExceptionUtil.throwAppException("累计未处理交易日志条数[" + tradeLogs.size() + "],超出日志保存能力");
        }
        tradeLogs.add(tradeLog);
    }

    /**
     * 同步写入日志
     *
     * @param tradeLog
     */
    public void synAddLog(SysTradeLog tradeLog) {
        LogManageService.getInstance().saveLog(tradeLog);
    }

    /**
     * 同步写入日志
     *
     * @param tradeLog
     */
    public void updateLog(SysTradeLog tradeLog) {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = transactionManager.getTransaction(def);
        SysTradeLogExample example = new SysTradeLogExample();
        example.createCriteria().andReqDateEqualTo(tradeLog.getReqDate()).andTradeCodeEqualTo(tradeLog.getTradeCode()).andTransSeqEqualTo(tradeLog.getTransSeq());
        tradeLogDAO.updateByExampleSelective(tradeLog, example);
        transactionManager.commit(status);
    }

    /**
     * 独立事务记录日志
     *
     * @param tradeLog
     */
    public void saveLog(SysTradeLog tradeLog) {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = transactionManager.getTransaction(def);
        tradeLogDAO.insert(tradeLog);
        transactionManager.commit(status);
    }


    public void saveLogBatch(List<SysTradeLog> tradeLogs) {
        if (null == tradeLogs || tradeLogs.size() == 0) {
            return;
        }
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus status = transactionManager.getTransaction(def);
        tradeLogDAO.insertBatch(tradeLogs);
        transactionManager.commit(status);
    }


    public int queueSize() {
        return tradeLogs.size();
    }

}
